You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
4.6 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
7 years ago
  1. package cassandra
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/gocql/gocql"
  6. "github.com/chrislusf/seaweedfs/weed/filer"
  7. "github.com/chrislusf/seaweedfs/weed/glog"
  8. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  9. "github.com/chrislusf/seaweedfs/weed/util"
  10. )
  11. func init() {
  12. filer.Stores = append(filer.Stores, &CassandraStore{})
  13. }
  14. type CassandraStore struct {
  15. cluster *gocql.ClusterConfig
  16. session *gocql.Session
  17. }
  18. func (store *CassandraStore) GetName() string {
  19. return "cassandra"
  20. }
  21. func (store *CassandraStore) Initialize(configuration util.Configuration, prefix string) (err error) {
  22. return store.initialize(
  23. configuration.GetString(prefix+"keyspace"),
  24. configuration.GetStringSlice(prefix+"hosts"),
  25. )
  26. }
  27. func (store *CassandraStore) initialize(keyspace string, hosts []string) (err error) {
  28. store.cluster = gocql.NewCluster(hosts...)
  29. store.cluster.Keyspace = keyspace
  30. store.cluster.Consistency = gocql.LocalQuorum
  31. store.session, err = store.cluster.CreateSession()
  32. if err != nil {
  33. glog.V(0).Infof("Failed to open cassandra store, hosts %v, keyspace %s", hosts, keyspace)
  34. }
  35. return
  36. }
  37. func (store *CassandraStore) BeginTransaction(ctx context.Context) (context.Context, error) {
  38. return ctx, nil
  39. }
  40. func (store *CassandraStore) CommitTransaction(ctx context.Context) error {
  41. return nil
  42. }
  43. func (store *CassandraStore) RollbackTransaction(ctx context.Context) error {
  44. return nil
  45. }
  46. func (store *CassandraStore) InsertEntry(ctx context.Context, entry *filer.Entry) (err error) {
  47. dir, name := entry.FullPath.DirAndName()
  48. meta, err := entry.EncodeAttributesAndChunks()
  49. if err != nil {
  50. return fmt.Errorf("encode %s: %s", entry.FullPath, err)
  51. }
  52. if len(entry.Chunks) > 50 {
  53. meta = util.MaybeGzipData(meta)
  54. }
  55. if err := store.session.Query(
  56. "INSERT INTO filemeta (directory,name,meta) VALUES(?,?,?) USING TTL ? ",
  57. dir, name, meta, entry.TtlSec).Exec(); err != nil {
  58. return fmt.Errorf("insert %s: %s", entry.FullPath, err)
  59. }
  60. return nil
  61. }
  62. func (store *CassandraStore) UpdateEntry(ctx context.Context, entry *filer.Entry) (err error) {
  63. return store.InsertEntry(ctx, entry)
  64. }
  65. func (store *CassandraStore) FindEntry(ctx context.Context, fullpath util.FullPath) (entry *filer.Entry, err error) {
  66. dir, name := fullpath.DirAndName()
  67. var data []byte
  68. if err := store.session.Query(
  69. "SELECT meta FROM filemeta WHERE directory=? AND name=?",
  70. dir, name).Consistency(gocql.One).Scan(&data); err != nil {
  71. if err != gocql.ErrNotFound {
  72. return nil, filer_pb.ErrNotFound
  73. }
  74. }
  75. if len(data) == 0 {
  76. return nil, filer_pb.ErrNotFound
  77. }
  78. entry = &filer.Entry{
  79. FullPath: fullpath,
  80. }
  81. err = entry.DecodeAttributesAndChunks(util.MaybeDecompressData(data))
  82. if err != nil {
  83. return entry, fmt.Errorf("decode %s : %v", entry.FullPath, err)
  84. }
  85. return entry, nil
  86. }
  87. func (store *CassandraStore) DeleteEntry(ctx context.Context, fullpath util.FullPath) error {
  88. dir, name := fullpath.DirAndName()
  89. if err := store.session.Query(
  90. "DELETE FROM filemeta WHERE directory=? AND name=?",
  91. dir, name).Exec(); err != nil {
  92. return fmt.Errorf("delete %s : %v", fullpath, err)
  93. }
  94. return nil
  95. }
  96. func (store *CassandraStore) DeleteFolderChildren(ctx context.Context, fullpath util.FullPath) error {
  97. if err := store.session.Query(
  98. "DELETE FROM filemeta WHERE directory=?",
  99. fullpath).Exec(); err != nil {
  100. return fmt.Errorf("delete %s : %v", fullpath, err)
  101. }
  102. return nil
  103. }
  104. func (store *CassandraStore) ListDirectoryPrefixedEntries(ctx context.Context, fullpath util.FullPath, startFileName string, inclusive bool, limit int, prefix string) (entries []*filer.Entry, err error) {
  105. return nil, filer.ErrUnsupportedListDirectoryPrefixed
  106. }
  107. func (store *CassandraStore) ListDirectoryEntries(ctx context.Context, fullpath util.FullPath, startFileName string, inclusive bool,
  108. limit int) (entries []*filer.Entry, err error) {
  109. cqlStr := "SELECT NAME, meta FROM filemeta WHERE directory=? AND name>? ORDER BY NAME ASC LIMIT ?"
  110. if inclusive {
  111. cqlStr = "SELECT NAME, meta FROM filemeta WHERE directory=? AND name>=? ORDER BY NAME ASC LIMIT ?"
  112. }
  113. var data []byte
  114. var name string
  115. iter := store.session.Query(cqlStr, string(fullpath), startFileName, limit).Iter()
  116. for iter.Scan(&name, &data) {
  117. entry := &filer.Entry{
  118. FullPath: util.NewFullPath(string(fullpath), name),
  119. }
  120. if decodeErr := entry.DecodeAttributesAndChunks(util.MaybeDecompressData(data)); decodeErr != nil {
  121. err = decodeErr
  122. glog.V(0).Infof("list %s : %v", entry.FullPath, err)
  123. break
  124. }
  125. entries = append(entries, entry)
  126. }
  127. if err := iter.Close(); err != nil {
  128. glog.V(0).Infof("list iterator close: %v", err)
  129. }
  130. return entries, err
  131. }
  132. func (store *CassandraStore) Shutdown() {
  133. store.session.Close()
  134. }